﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml.Serialization;
using GMap.NET;
using GMap.NET.WindowsPresentation;
using MyPoints.Model;
using Microsoft.Win32;
using MyPoints.UserControls;
using System.Reflection;
using System.Diagnostics;

namespace MyPoints
{
  /// <summary>
  /// Interaction logic for MainWindow.xaml
  /// </summary>
  public partial class MainWindow : Window
  {

    public MainWindow()
    {
      string settFile = "AppSettings\\appSettings.xml";
      Shared.sett = XmlBo.LoadXml<eSettingsType>(settFile);

      InitializeComponent();

      ctrWptList.Init();
      ctrMap.Init();
      RedrawAll();

      ctrWptList.WptClick += CtrWptList_WptClick;
      ctrMap.WptSelected += CtrMap_WptSelected;
      ctrMap.NewWptRequest += CtrMap_NewWptRequest;
      ctrWptDetail.ValueCategoryChanged += CtrWptDetail_ValueCategoryChanged;
      ctrWptDetail.ValueTitleChanged += CtrWptDetail_ValueTitleChanged;
    }

    private void CtrWptDetail_ValueTitleChanged(wptType sender)
    {
      ctrWptList.UpdateWptsTitle(sender);
      ctrMap.UpdateWptsTitle(sender);
    }

    private void CtrWptDetail_ValueCategoryChanged(wptType sender)
    {
      ctrWptList.UpdateWptsCategory(sender);
      ctrMap.UpdateWptsCategory(sender);
    }

    private void CtrMap_NewWptRequest(UserControls.Map sender, PointLatLng point)
    {
      CreateNewWpt(point);
    }

    private void CtrWptList_WptClick(UserControls.WptList sender, wptType wpt)
    {
      SelectWpt(wpt, false, true);
    }

    private void CtrMap_WptSelected(UserControls.Map sender, wptType wpt)
    {
      SelectWpt(wpt, true, false);
    }

    private void SelectWpt(wptType wpt, bool selectInList, bool selectOnMap)
    {
      if (selectInList) { }
      if (selectOnMap)
      {
        ctrMap.SelectWpt(wpt);
      }
      ctrWptDetail.Value = wpt;
      ctrWptDetail.Visibility = Visibility.Visible;
    }

    private void LoadData()
    {
      string fileName;
      OpenFileDialog openFileDialog = new OpenFileDialog();
      openFileDialog.Filter = "Gpx file (*.gpx)|*.GPX|Xml file (*.xml)|*.XML|All files (*.*)|*.*";
      openFileDialog.FileName = Shared.sett.user.lastFileName;
      if (openFileDialog.ShowDialog() == true)
        fileName = openFileDialog.FileName;
      else
        return;

      gpxType gpx = XmlBo.LoadXml<gpxType>(fileName);
      Shared.model = new GpxModel(gpx);

      Shared.sett.user.lastFileName = fileName;
    }

    private void btnSave_Click(object sender, RoutedEventArgs e)
    {
      string fileName;
      SaveFileDialog saveFileDialog = new SaveFileDialog();
      saveFileDialog.Filter = "Gpx file (*.gpx)|*.GPX|Xml file (*.xml)|*.XML|All files (*.*)|*.*";
      saveFileDialog.FileName = Shared.sett.user.lastFileName;
      if (saveFileDialog.ShowDialog() == true)
        fileName = saveFileDialog.FileName;
      else
        return;

      try
      {
        XmlBo.SaveXml<gpxType>(Shared.model.ToXmlObject(), fileName);
      }
      catch (Exception ex)
      {
        MessageBox.Show("Saving failed. " + ex.Message, "...", MessageBoxButton.OK);
      }

      MessageBox.Show("Saved.", "...", MessageBoxButton.OK);
    }

    private void btnOpen_Click(object sender, RoutedEventArgs e)
    {
      try
      {
        LoadData();
        RedrawAll();
      }
      catch (Exception ex)
      {
        MessageBox.Show("Loading failed." + ex.Message, "...", MessageBoxButton.OK);
      }
      MessageBox.Show("Loaded.", "...", MessageBoxButton.OK);
    }

    private void btnNew_Click(object sender, RoutedEventArgs e)
    {
      Shared.model = new GpxModel();
      Shared.sett.user.lastFileName = "";
      RedrawAll();
    }

    private void RedrawAll(FilterControl.VM filter = null)
    {
      var wpts = Shared.model.Wpts;
      if (filter != null)
      {
        wpts = FilterBy(wpts, filter);
      }

      ctrWptList.EraseAllWpt();
      ctrWptList.AddWpts(wpts);
      ctrWptList.CollapseAll();
      ctrWptList.Expand(null);

      ctrMap.ClearWpts();
      ctrMap.AddWpts(wpts);
    }

    private wptType[] FilterBy(wptType[] wpts, FilterControl.VM filter)
    {
      var lst = wpts.ToList();
      List<wptType> ret = new List<wptType>();

      foreach (var wpt in wpts)
      {
        List<string> txts = new List<string>();
        if (filter.Option.HasFlag(FilterControl.VM.eOption.Category))
          txts.Add(wpt.Category);
        if (filter.Option.HasFlag(FilterControl.VM.eOption.Comment))
          txts.Add(wpt.cmt);
        if (filter.Option.HasFlag(FilterControl.VM.eOption.Description))
          txts.Add(wpt.desc);
        if (filter.Option.HasFlag(FilterControl.VM.eOption.Title))
          txts.Add(wpt.Title);

        if (IsAcceptedByFilter(txts.ToArray(), filter.Expression, filter.IsRegex))
          ret.Add(wpt);
      }

      return ret.ToArray();
    }

    private bool IsAcceptedByFilter(string[] texts, string expression, bool useRegex)
    {
      bool ret = false;

      if (!useRegex)
        expression = expression.ToLower();
      foreach (var text in texts)
      {
        if (text == null) continue;
        if (useRegex)
          ret = System.Text.RegularExpressions.Regex.IsMatch(text, expression);
        else
          ret = text.ToLower().Contains(expression);
        if (ret)
          break;
      }

      return ret;
    }

    private void btnNewMarker_Click(object sender, RoutedEventArgs e)
    {
      CreateNewWpt();
    }

    private void btnDeleteMarker_Click(object sender, RoutedEventArgs e)
    {
      wptType selected = ctrWptDetail.Value;
      if (selected == null)
      {
        MessageBox.Show("No waypoint selected. Select waypoint to be deleted first.", "...", MessageBoxButton.OK);
        return;
      }

      if (MessageBox.Show("Are you sure about deleting point " + selected.name + "?", "...", MessageBoxButton.YesNo) == MessageBoxResult.No)
        return;

      Shared.model.RemoveWpt(selected);
      ctrMap.RemoveWpt(selected);
      ctrWptList.RemoveWpt(selected);
      ctrWptDetail.Value = null;
      ctrWptDetail.Visibility = Visibility.Collapsed;
    }

    private void CreateNewWpt()
    {
      PointLatLng center = ctrMap.Center;
      CreateNewWpt(center);
    }

    private void CreateNewWpt(GMap.NET.PointLatLng initPoint)
    {
      wptType wpt = new wptType();
      wpt.name = Shared.NEW_WPT_NAME;
      wpt.lat = (decimal)initPoint.Lat;
      wpt.lon = (decimal)initPoint.Lng;

      Shared.model.AddWpt(wpt);
      ctrWptList.AddWpt(wpt);
      ctrWptList.Expand(wpt.Category);
      ctrMap.AddWpt(wpt);

      SelectWpt(wpt, true, true);
    }

    private void ctrFilter_FilterSet(UserControls.FilterControl sender, UserControls.FilterControl.VM filter)
    {
      RedrawAll(filter);
    }

    private void btnStretch_Click(object sender, RoutedEventArgs e)
    {
      ctrMap.AimToPoints();
    }

    private void btnSettings_Click(object sender, RoutedEventArgs e)
    {
      string settFileName =
        System.IO.Path.Combine(
        System.AppDomain.CurrentDomain.BaseDirectory,
        "AppSettings/AppSettings.xml");
      var p = new ProcessStartInfo(settFileName);
      Process.Start(p);
    }

    private void btnAbout_Click(object sender, RoutedEventArgs e)
    {
      AboutWindow f = new AboutWindow();
      f.ShowDialog();
    }

  }
}
